<?php

namespace EasyWaf;

class Check
{

    /**
     * getFilter
     * @var string
     */
    protected $getFilter = "\\<.+javascript:window\\[.{1}\\\\x|\.\.\/|\.\/|invokefunction|call_user_func|call_user_func_array|<.*=(&#\\d+?;?)+?>|<.*(data|src)=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\()|<[a-z]+?\\b[^>]*?\\bon([a-z]{4,})\s*?=|^\\+\\/v(8|9)|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";

    /**
     * postFilter
     * @var string
     */
    protected $postFilter = "<.*=(&#\\d+?;?)+?>|<.*data=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\()|<[^>]*?\\b(onerror|onmousemove|onload|onclick|onmouseover)\\b|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";

    /**
     * cookieFilter
     * @var string
     */
    protected $cookieFilter = "benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\(|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";

    /**
     * userAgentFilter
     * @var string
     */
    protected $userAgentFilter = "GPTBot|Qwantify|DotBot|AhrefsBot|FriendlyCrawler|msnbot|YodaoBot|PanguBot|iaskspider|SemrushBot|facebookexternalhit|Amazonbot|python|httrack|apache-httpclient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|parser|libwww|bbbike|sqlmap|w3af|owasp|nikto|fimap|havij|zmeu|babykrokodil|netsparker|httperf|sf|Go-http-client";

    public function __construct()
    {
        try {
            $this->checkGet();
            $this->checkPost();
            $this->checkCookie();
            $this->checkUserAgent();
        } catch (Exception $exception) {
            http_response_code(403);
            $tpl = __DIR__ . '/tpl/stop.tpl';
            $message = file_get_contents($tpl);
            echo $message;
            exit();
        }
    }

    /**
     * @throws Exception
     */
    private function checkGet()
    {
        if (Config::get(Enums::OpenWebScanGet)) {
            $char = Utils::match($_GET, $this->getFilter);
            if ($char) {
                throw new Exception("Get请求包含非法字符串:" . $char);
            }
        }
    }

    /**
     * @throws Exception
     */
    private function checkPost()
    {
        if (Config::get(Enums::OpenWebScanPost)) {
            $char = Utils::match($_POST, $this->postFilter);
            if ($char) {
                throw new Exception("Post请求包含非法字符串:" . $char);
            }
        }
    }

    /**
     * @throws Exception
     */
    private function checkCookie()
    {
        if (Config::get(Enums::OpenWebScanCookie)) {
            $char = Utils::match($_COOKIE, $this->cookieFilter);
            if ($char) {
                throw new Exception("Cookie请求包含非法字符串:" . $char);
            }
        }
    }

    /**
     * @throws Exception
     */
    private function checkUserAgent()
    {
        if (Config::get(Enums::OpenWebScanUserAgent)) {
            $userAgent = empty($_SERVER['HTTP_USER_AGENT']) ? [] : ['HTTP_USER_AGENT' => $_SERVER['HTTP_USER_AGENT']];
            $char = Utils::match($userAgent, $this->userAgentFilter);
            if ($char) {
                throw new Exception("USER_AGENT请求包含非法字符串:" . $char);
            }
        }
    }
}